package emqx.test.emqx;

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import java.nio.charset.StandardCharsets;

/**
 * 这是一个要交给mqttClient连接对象使用的回调对象
 * 包含一个底层连接和emqx通信的4个回调时间点
 */
@Slf4j
public class MqttMyCallback implements MqttCallbackExtended {
    private MqttClient mqttClient;
    public MqttMyCallback(MqttClient mqttClient){
        this.mqttClient=mqttClient;
    }
    /**
     * 回调时机: 客户端mqttClient成功建立与emqx服务端连接关系时调用
     * boolean reconnect: true表示本次连接是重连,false表示第一次连接
     * String serverUri: 实际连接的地址
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        if(reconnect){
            log.info("自动重连成功,borker服务端地址:{}",serverURI);
        }else{
            log.info("首次连接成功,borker服务端地址:{}",serverURI);
        }
        //利用当前回调类所属的客户端,进行连接成功之后的主题订阅 如果当前回调类所属客户端没有订阅任何主题
        //不可能消费主题的消息
        try{
            mqttClient.subscribe("$share/group1/topic01");
            //TODO 根据主题对应的业务 客户端可以订阅多个主题
        }catch (Exception e){
            log.error("订阅主题失败",e);
        }

    }

    /**
     * 回调时机: mqttClient连接断开时调用
     * Throwable cause: 连接断开原因
     * 如果设置了setAutomaticReconnect(true).自动重连,否则这个代码 手动处理重新连接
     */
    @Override
    public void connectionLost(Throwable cause) {
        log.info("连接断开,原因:{}",cause.getMessage());
    }

    /**
     * 回调时机: mqttClient通过订阅主题 获取到消息的时候 所以这个方法中应该包含消费逻辑
     * String topic: 消息来源主题
     * MqttMessage message: 消息对象(payLoad,qos retain)
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        log.info("收到消息,来源topic:{},消息内容:{}",topic,
                new String(message.getPayload(), StandardCharsets.UTF_8));
    }

    /**
     * 回调时机: mqttClient投递发送消息的时候 接收到服务端反馈确认成功的 消息发送成功调用
     * 但是只有在QOS>0的时候才有效 因为  QOS=0 客户端不关心成功失败.
     * IMqttDeliveryToken token: 包含消息ID等上下文信息 原始消息就在token里
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        //可以从token获得发送的原始消息
        String body=null;
        try{
            MqttMessage message = token.getMessage();
            body=new String(message.getPayload(),StandardCharsets.UTF_8);
        }catch (Exception e){
            log.error("获取原始消息失败",e);
        }
        log.info(
                "消息投递完成,消息ID:{},消息原始内容:{}",
                token.getMessageId(),body
                );
    }
}
